/*
 * USB OTG Core functionality common for both Host and Device
 * functionality.
 *
 * Copyright (c) 2012 Alpscale 
 *
 */


#include "musb_core.h"
struct musb_regs *musbr;

/*
 * program the mentor core to start (enable interrupts, dma, etc.)
 */
void musb_start(void)
{
#if defined(CONFIG_MUSB_HCD)
	uint8_t devctl;
//	uint8_t busctl;
#endif

	/* disable all interrupts */
	musbr->intrtxe1=0;
	musbr->intrtxe2=0;
	musbr->intrrxe1=0;
	musbr->intrrxe2=0;
	//writeb(0, &musbr->testmode);

	/* put into basic highspeed mode and start session */
//	writeb(MUSB_POWER_HSENAB, &musbr->power);
#if defined(CONFIG_MUSB_HCD)
	/* Program PHY to use EXT VBUS if required */
	devctl = readb(&musbr->devctl);
	writeb(devctl | MUSB_DEVCTL_SESSION, &musbr->devctl);
#endif
}

#ifdef MUSB_NO_DYNAMIC_FIFO
# define config_fifo(dir, idx, addr)
#else

/*
#define config_txfifo(idx, addr) \
	do { \
		writeb(idx, &musbr->txfifosz); \
		writew(addr>>3 , &musbr->txfifoadd); \
	} while (0)

#define config_rxfifo(idx, addr) \
	do { \
		writeb(idx, &musbr->rxfifosz); \
		writew(addr>>3, &musbr->rxfifoadd); \
	} while (0)
*/
#endif

/*
 * This function configures the endpoint configuration. The musb hcd or musb
 * device implementation can use this function to configure the endpoints
 * and set the FIFO sizes. Note: The summation of FIFO sizes of all endpoints
 * should not be more than the available FIFO size.
 *
 * epinfo	- Pointer to EP configuration table
 * cnt		- Number of entries in the EP conf table.
 */
void musb_configure_ep(const struct musb_epinfo *epinfo, uint8_t cnt)
{
	uint8_t csr;
	uint16_t temp16;
	uint16_t fifoaddr = 64; /* First 64 bytes of FIFO reserved for EP0 */
	uint32_t fifosize;
	uint8_t  idx;

	
	while (cnt--) {
		/* prepare fifosize to write to register */
		fifosize = epinfo->epsize >> 3;
		idx = ffs(fifosize) - 1;

		//writeb(epinfo->epnum, &musbr->index);
		musbr->index = epinfo->epnum;

		if (epinfo->epdir) {
			/* Configure fifo size and fifo base address */
			//config_txfifo(idx, fifoaddr);
			temp16 = (fifoaddr>>3)|(idx<<13);
			musbr->txfifo1=temp16&0xFF;
			musbr->txfifo2=(temp16>>8)&0xFF;

			csr = musbr->txcsr1;
#if defined(CONFIG_MUSB_HCD)
			/* clear the data toggle bit */
			musbr->txcsr1= csr | MUSB_TXCSR_CLRDATATOG;
#endif
			/* Flush fifo if required */
			if (csr & MUSB_TXCSR_TXPKTRDY)
				musbr->txcsr1=csr | MUSB_TXCSR_FLUSHFIFO;
		} else {
			/* Configure fifo size and fifo base address */
			//config_rxfifo(idx, fifoaddr);
			temp16 = (fifoaddr>>3)|(idx<<13);
			musbr->rxfifo1=temp16&0xFF;
			musbr->rxfifo2=(temp16>>8)&0xFF;

			csr = musbr->rxcsr1;
#if defined(CONFIG_MUSB_HCD)
			/* clear the data toggle bit */
			musbr->rxcsr1=csr | MUSB_RXCSR_CLRDATATOG;
#endif
			/* Flush fifo if required */
			if (csr & MUSB_RXCSR_RXPKTRDY)
				musbr->rxcsr1=csr | MUSB_RXCSR_FLUSHFIFO;
		}
		fifoaddr += epinfo->epsize;
		epinfo++;
	}
}

/*
 * This function writes data to endpoint fifo
 *
 * ep		- endpoint number
 * length	- number of bytes to write to FIFO
 * fifo_data	- Pointer to data buffer that contains the data to write
 */
//__attribute__((weak))
void write_fifo(uint8_t ep, uint32_t length, void *fifo_data)
{
	uint32_t addr = (uint32_t)fifo_data;

	/* select the endpoint index */
	writeb(ep, &musbr->index);

	//write byte
	while(addr & 0x3){
		musbr->fifox[ep*4] = inb(addr);
		addr++;
		length--;
	}

	//write dword
	while (length >= 4){
		outl(inl(addr), USB_BASE+0x20+ep*4);
		addr += 4;
		length -= 4;
	}

	//write byte
	while(length){
		musbr->fifox[ep*4] = inb(addr);
		addr++;
		length--;
	}
}

/*
 * This function reads data from endpoint fifo
 *
 * ep           - endpoint number
 * length       - number of bytes to read from FIFO
 * fifo_data    - pointer to data buffer into which data is read
 */
//__attribute__((weak))
void read_fifo(uint8_t ep, uint32_t length, void *fifo_data)
{
	uint32_t addr = (uint32_t)fifo_data;

	/* select the endpoint index */
	writeb(ep, &musbr->index);

	//read byte
	while(addr & 0x3){
		outb(musbr->fifox[ep*4], addr);
		addr++;
		length--;
	}

	//read dword
	while (length >= 4){
		outl(inl(USB_BASE+0x20+ep*4), addr);
		addr += 4;
		length -= 4;
	}

	//read byte
	while(length){
		outb(musbr->fifox[ep*4], addr);
		addr++;
		length--;
	}
}

